#include "TexturePNG.h"

TexturePNG::TexturePNG()
{}

TexturePNG::~TexturePNG()
{}

//ITexture* TexturePNG::Create(const std::wstring& path)
//{
//		int x, y;
//		png_bytep header;    // 8 is the maximum size that can be checked
//		const wchar_t* file_name = path.c_str();
//
//		* open file and test for it being a png */
//		FILE *fp = _wfopen(file_name, L"rb");
//		if (!fp)
//				return NULL;//abort_("[read_png_file] File %s could not be opened for reading", file_name);
//		fread(header, 1, 8, fp);
//		if (png_sig_cmp(header, 0, 8))
//				return NULL;//abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);
//
//
//		* initialize stuff */
//		TexturePNG* texture = new TexturePNG();
//		texture->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
//
//		if (!texture->png_ptr)
//				return NULL;//abort_("[read_png_file] png_create_read_struct failed");
//
//		texture->info_ptr = png_create_info_struct(texture->png_ptr);
//		if (!texture->info_ptr)
//				return NULL;//abort_("[read_png_file] png_create_info_struct failed");
//
//		if (setjmp(png_jmpbuf(texture->png_ptr)))
//				return NULL;//abort_("[read_png_file] Error during init_io");
//
//		png_init_io(texture->png_ptr, fp);
//		png_set_sig_bytes(texture->png_ptr, 8);
//
//		png_read_info(texture->png_ptr, texture->info_ptr);
//
//		texture->width		= png_get_image_width(texture->png_ptr, texture->info_ptr);
//		texture->height		= png_get_image_height(texture->png_ptr, texture->info_ptr);
//		texture->color_type	= png_get_color_type(texture->png_ptr, texture->info_ptr);
//		texture->bit_depth	= png_get_bit_depth(texture->png_ptr, texture->info_ptr);
//
//		texture->number_of_passes = png_set_interlace_handling(texture->png_ptr);
//		png_read_update_info(texture->png_ptr, texture->info_ptr);
//		
//		* read file */
//		if (setjmp(png_jmpbuf(texture->png_ptr)))
//				return NULL;//abort_("[read_png_file] Error during read_image");
//
//		texture->row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * texture->height);
//		for (y = 0; y < texture->height; y++)
//				texture->row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(texture->png_ptr, texture->info_ptr));
//
//		png_read_image(texture->png_ptr, texture->row_pointers);
//
//		fclose(fp);
//
//		return texture;
//}
ITexture* TexturePNG::Create(const std::wstring& path)
{	
	TexturePNG* texinfo;
	const wchar_t* filename = path.c_str();
	png_byte header[8];
	png_structp png_ptr;
	png_infop info_ptr;
	int bit_depth, color_type;
	FILE *fp = NULL;
	png_bytep *row_pointers = NULL;
	png_uint_32 w, h;
	int i;

	/* Open image file */
	fp = _wfopen (filename, L"rb");
	if (!fp)
	{
		fwprintf (stderr, L"error: couldn't open \"%s\"!\n", filename);
		return NULL;
	}

	/* Read header */
	fread (header, 1, sizeof (header), fp);

	/* Check for valid header */
	if (!png_check_sig (header, sizeof (header)))
	{
		fwprintf (stderr, L"error: \"%s\" is not a valid PNG image!\n",
			filename);
		fclose (fp);
		return NULL;
	}

	/* Create a png read struct */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr)
	{
		fclose (fp);
		return NULL;
	}

	/* Create a png info struct */
	info_ptr = png_create_info_struct (png_ptr);
	if (!info_ptr)
	{
		fclose (fp);
		png_destroy_read_struct (&png_ptr, NULL, NULL);
		return NULL;
	}

	/* Create our OpenGL texture object */
	//texinfo = (struct gl_texture_t *)
	//malloc (sizeof (struct gl_texture_t));
	texinfo = new TexturePNG();

	/* Initialize the setjmp for returning properly after a libpng
		error occured */
	if (setjmp (png_jmpbuf (png_ptr)))
	{
		fclose (fp);
		png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

		if (row_pointers)
			free (row_pointers);

		if (texinfo)
		{
			if (texinfo->m_texels)
				free (texinfo->m_texels);

			free (texinfo);
		}
		return NULL;
	}

	/* Setup libpng for using standard C fread() function
		with our FILE pointer */
	png_init_io (png_ptr, fp);

	/* Tell libpng that we have already read the header */
	png_set_sig_bytes (png_ptr, sizeof (header));

	/* Read png info */
	png_read_info (png_ptr, info_ptr);

	/* Get some usefull information from header */
	bit_depth = png_get_bit_depth (png_ptr, info_ptr);
	color_type = png_get_color_type (png_ptr, info_ptr);

	/* Convert index color images to RGB images */
	if (color_type == PNG_COLOR_TYPE_PALETTE)
		png_set_palette_to_rgb (png_ptr);

	/* Convert 1-2-4 bits grayscale images to 8 bits
		grayscale. */
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_gray_1_2_4_to_8 (png_ptr);

	if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha (png_ptr);

	if (bit_depth == 16)
		png_set_strip_16 (png_ptr);
	else if (bit_depth < 8)
		png_set_packing (png_ptr);

	/* Update info structure to apply transformations */
	png_read_update_info (png_ptr, info_ptr);

	/* Retrieve updated information */
	png_get_IHDR (png_ptr, info_ptr, &w, &h, &bit_depth,
		&color_type, NULL, NULL, NULL);
	texinfo->m_width = w;
	texinfo->m_height = h;

	/* Get image format and components per pixel */
	GetInfo (color_type, texinfo);

	/* We can now allocate memory for storing pixel data */
	texinfo->m_texels = (GLubyte *)malloc (sizeof (GLubyte) * texinfo->m_width
			* texinfo->m_height * texinfo->m_internalFormat);

	/* Setup a pointer array.  Each one points at the begening of a row. */
	row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * texinfo->m_height);

	for (i = 0; i < texinfo->m_height; ++i)
	{
	#if 0
		row_pointers[i] = (png_bytep)(texinfo->m_texels +
			((texinfo->m_height - (i + 1)) * texinfo->m_width * texinfo->m_internalFormat));
	#else
		row_pointers[i] = (png_bytep)(texinfo->m_texels +
			(texinfo->m_width * i * texinfo->m_internalFormat));
	#endif
	}

	/* Read pixel data using row pointers */
	png_read_image (png_ptr, row_pointers);

	/* Finish decompression and release memory */
	png_read_end (png_ptr, NULL);
	png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

	/* We don't need row pointers anymore */
	free (row_pointers);

	fclose (fp);
	return texinfo;
}

void TexturePNG::GetInfo(int colorType, TexturePNG* textureInfo)
{
	switch (colorType)
	{
	case PNG_COLOR_TYPE_GRAY:
		textureInfo->m_format = GL_LUMINANCE;
		textureInfo->m_internalFormat = 1;
		break;
	case PNG_COLOR_TYPE_GRAY_ALPHA:
		textureInfo->m_format = GL_LUMINANCE_ALPHA;
		textureInfo->m_internalFormat = 2;
		break;
	case PNG_COLOR_TYPE_RGB:
		textureInfo->m_format = GL_RGB;
		textureInfo->m_internalFormat = 3;
		break;
	case PNG_COLOR_TYPE_RGB_ALPHA:
		textureInfo->m_format = GL_RGBA;
		textureInfo->m_internalFormat = 4;
		break;
	default:
		/* Badness */
		break;
	}
}